import xCubeData from './xCubeData.js';
import xFilter from "./xFilter.js";
import {replaceByObj,saveAsXmlXls,saveAsCsv,jsonToCsv} from "./xUtil.js";
import xmlTable from './xmlTable.js';
import xID from './xID.js';
import cell from "./cell.js";

const tmplBase =`<div class="{{class}}" >             
                     <table>
                       <thead></thead>
                       <tbody></tbody>
                     </table>                          
                   <div type="filter-panel" style="position: absolute;z-index:100; display: none"></div> 
                   <div type="spin" class="spin" style="display: none" > 
                     <div class="spinner-border text-primary" >
                        <span class="visually-hidden">Loading...</span>
                     </div>
                    </div>                       
                 </div>`;
const tmplTd ='<td {{colspan}} {{rowspan}} type="{{type}}">{{html}}</td>';
const tmplTr= '<tr>{{html}}</tr>';




/*
*/
export default class xCube{
    $root;
    $head;
    $body;

    vCubeId =xID.getID();
    vCfg;
    vCubeData = new xCubeData();
    vFilter;
    /*定义变量 结束*/
    // 构造函数
    constructor(cfg) {
        this.vCfg =cfg;
        this.$root = $('#' + cfg.el);
        this.$root.html(replaceByObj(tmplBase,{class:cfg.style||'cube'}));
        this.$head = this.$root.find('thead');
        this.$body = this.$root.find('tbody');
        this.$spin = this.$root.find('[type="spin"]');
        this.vFilter = new xFilter(this.$root.find('[type="filter-panel"]'));
        this.$root.on('click', 'i[type="filter"]', this.evFilter.bind(this));
        this.$root.on('click', '[type="V"]', this.evValueClick.bind(this));
        this.$root.on('click', '[type="Y"]', this.evYClick.bind(this));
        this.$root.on('click', '[type="X"]', this.evXClick.bind(this));

    };

    refresh(){
        this.$spin.show();
        setTimeout(this.asyncRender.bind(this),50);
    }

    asyncRender(){
        this.vCubeData.prepare(this.vCfg);
        if(this.vCfg.valuesOn!='Y')
            this.renderCube();
        else
            this.renderCubeOnY();
        this.$spin.hide();
    }

    init(){
        this.refresh();
    }


    renderTd(item,key,type,pos){
        //let factor = type=='X'?this.vCfg.values.length:1;
        //span factor 要根据 type  和 valuesOn 来判断;
        let factor =this.vCfg.values.length;
        let colspan = (item && item._colspan)?item._colspan:1;
        let rowspan = (item && item._rowspan)?item._rowspan:1;
        let html = '';
        let cfg = {item,key,type,pos};
        switch(type){
            case 'X':
                if(!(this.vCfg.valuesOn =='Y'))
                    colspan = colspan*factor;
                html = cell.renderPivotXCell(cfg);
                break;
            case 'Y':
                if(this.vCfg.valuesOn =='Y')
                    rowspan = rowspan*factor;
                html = cell.renderPivotYCell(cfg);
                break;
            case 'V':
                html = cell.renderPivotVCell(cfg);
                break;
            case 'YTitle':
                cfg.filterActive = this.vCubeData.isActiveFilter(key.$code)
                html = cell.renderPivotYTitle(cfg);
                break;
            case 'VTitle':
                html = cell.renderPivotVTitle(cfg);
                break;
            case 'XTitle':
                cfg.filterActive = this.vCubeData.isActiveFilter(key.$code)
                html = cell.renderPivotXTitle(cfg);
                break;
        }
        return replaceByObj(tmplTd,{colspan:colspan==1?'':'colspan="'+colspan+'"',
            rowspan:rowspan==1?'':'rowspan="'+rowspan+'"',html,type});
    }

    // Y title 和  V title 在一起了
    renderYVTitle(){
        let tds ='';
        for(let y of this.vCfg.keysY){
            tds += this.renderTd({_colspan:1,_rowspan:1},y,'YTitle')
        }

        for(let i=0;i<this.vCubeData.vLeafsX.length;i++){
            this.vCfg.values.forEach((key) =>
                tds += this.renderTd({},key,'VTitle'))
        }
        return tmplTr.replace('{{html}}',tds);
    }

    renderXTitle(i){
        return   this.renderTd({_colspan:this.vCfg.keysY.length,
                              _rowspan:1},this.vCfg.keysX[i],'XTitle')
    }

    renderX(){
        let trs ='';
        let tds;
        for(let i in this.vCubeData.vAxisXMatrix){
            tds = this.renderXTitle(i);
            for(let j in this.vCubeData.vAxisXMatrix[i]){
                let item = this.vCubeData.vAxisXMatrix[i][j];
                if(item){
                    tds += this.renderTd(item,null,'X');
                }
            }
            trs += tmplTr.replace('{{html}}',tds);
        }
        return trs + this.renderYVTitle();
    }

    renderY(i){
        let tds = '';
        for(let j in this.vCubeData.vAxisYMatrix[i]){
            let item = this.vCubeData.vAxisYMatrix[i][j];
            tds += this.renderTd(item,null,'Y')
        }
        return tds;
    }

    // render axis Y and Value;
    renderYV(){
        let trs ='';
        let tds;

        //首先要预置个存计算结果的 matrix 防止重复计算
        let vMatrix=[];

        for(let i=0;i<this.vCubeData.vLeafsY.length;i++){
            vMatrix.push([]);
            tds = this.renderY(i);
            for(let j=0;j<this.vCubeData.vLeafsX.length;j++){
                let slice = vMatrix[i][j];
                if (!slice) {
                    slice = {Y:this.vCubeData.vLeafsY[i],X:this.vCubeData.vLeafsX[j]};
                    let tuple = this.vCubeData.getTuple(slice.Y,slice.X);
                    slice.item = this.vCfg.callback(tuple);
                    vMatrix[i][j] = slice;
                }
                this.vCfg.values.forEach((key,index) =>{
                    let pos = j+','+i+','+index;
                    tds += this.renderTd(slice.item,key,'V',pos)
                })
            }
            trs += tmplTr.replace('{{html}}',tds);
        }
        return trs;
    }

    renderCube(){
        this.$head.html(this.renderX());
        this.$body.html(this.renderYV());
    }

    renderCubeOnY(){
        this.$head.html(this.renderXOnY());
        this.$body.html(this.renderYVOnY());
    }
    /*数据列 在 Y 上的情况*/
    renderXOnY(){
        let trs ='';
        let tds;
        for(let i=0;i<this.vCubeData.vAxisXMatrix.length;i++){
            tds ='';
            if(i==0){
                tds += this.renderYTitleOnY();
            }
            tds += this.renderXTitleOnY(i);
            for(let j in this.vCubeData.vAxisXMatrix[i]){
                let item = this.vCubeData.vAxisXMatrix[i][j];
                if(item){
                    tds += this.renderTd(item,null,'X');
                }
            }
            trs += tmplTr.replace('{{html}}',tds);
        }
        return trs;
    }

    renderYOnY(i){
        let tds = '';
        for(let j in this.vCubeData.vAxisYMatrix[i]){
            let item = this.vCubeData.vAxisYMatrix[i][j];
            if(item)
                 tds += this.renderTd(item,null,'Y')
        }
        return tds;
    }

    renderYTitleOnY(){
        let tds ='';
        for(let y of this.vCfg.keysY){
            tds += this.renderTd({_colspan:1,_rowspan:this.vCfg.keysX.length},
                                      y,'YTitle')
        }
        return tds;
    }

    renderXTitleOnY(i){
        return   this.renderTd({_colspan:1,
            _rowspan:1},this.vCfg.keysX[i],'XTitle')
    }

    renderYVOnY(){
        let trs ='';
        let tds;
        //首先要预置个存计算结果的 matrix 防止重复计算
        let vMatrix=[];
        for(let i=0;i<this.vCubeData.vLeafsY.length;i++) {
            vMatrix.push([]);
            /*
             renderY 要注意 1 : rowspan * factor
              空的点 不需要 render
            * */
            tds = this.renderYOnY(i);
            for (let j = 0; j < this.vCfg.values.length; j++) {
                /*
                * j==0 和上面的tds 是一行
                * j !=0 需要另起一行
                * */
                if (j != 0) {
                    trs += tmplTr.replace('{{html}}', tds);
                    tds = '';
                }
                // render 数据项目的 title

                tds +=  this.renderTd({},this.vCfg.values[j],'VTitle');
                for (let k = 0; k < this.vCubeData.vLeafsX.length; k++) {
                    let slice = vMatrix[i][k];
                    if (!slice) {
                        slice = {Y: this.vCubeData.vLeafsY[i], X: this.vCubeData.vLeafsX[k]};
                        let tuple = this.vCubeData.getTuple(slice.Y, slice.X);
                        slice.item = this.vCfg.callback(tuple);
                        vMatrix[i, k] = slice;
                    }
                    let pos = k+','+i+','+j;
                    tds += this.renderTd(slice.item, this.vCfg.values[j], 'V', pos)
                }
                //最后一行
                if (j == this.vCfg.values.length - 1)
                    trs += tmplTr.replace('{{html}}', tds);
            }
        }
        return trs;
    }

    evFilter(e){
        let field = e.target.parentNode.getAttribute("data-code") ;
        let filterCfg ={
                       data:this.vCubeData.getMapDataByField(field),
                       select:this.vCubeData.getSelectByField(field),
                       field,
                       ok:this.filterOk.bind(this)
        };

        this.vFilter.show(filterCfg,this.$root ,$(e.target));
    }

    // 过滤后的回调函数
    filterOk(field,select,allChecked){
        if(allChecked==1)
            delete this.vCubeData.vFilterKeys[field];
        else
            this.vCubeData.addSelect(field,select);
        this.refresh();
    }

    evValueClick(e){
        if(this.vCfg.event && this.vCfg.event.OnValueClick){
            let code = e.currentTarget.getAttribute("data-code");
            let pos = code.split(',');
            let [x,y,z] = [pos[0],pos[1],pos[2]];
            //所有相关数据 ，和对应的 value key
            let tuple = this.vCubeData.getTuple(this.vCubeData.vLeafsY[y], this.vCubeData.vLeafsX[x]);
            this.vCfg.event.OnValueClick(tuple,this.vCubeData.vLeafsX[x].code,
            this.vCubeData.vLeafsY[y].code,this.vCfg.values[z]);
        }
    }

    evYClick(e){
        if(this.vCfg.event && this.vCfg.event.OnYClick){
            let code = e.currentTarget.getAttribute("data-code");
            let codeArray = code.split(',');
            this.vCfg.event.OnYClick(codeArray[codeArray.length-1],this.vCfg.keysY[codeArray.length-1]);
        }
    }

    evXClick(e){
        if(this.vCfg.event && this.vCfg.event.OnXClick){
            let code = e.currentTarget.getAttribute("data-code");
            let codeArray = code.split(',');
            this.vCfg.event.OnXClick(codeArray[codeArray.length-1],this.vCfg.keysX[codeArray.length-1]);
        }
    }

    saveCsv(fileName){
        saveAsCsv(fileName+'.csv',jsonToCsv(json));
    }

    saveXls(fileName){
        saveAsXmlXls(fileName+'.xls',new xmlTable().toXmlTable(this.$table));
    }

}